import * as cc from 'cc';
import { FixedUpdate } from 'db://assets/component/shadule/FixedUpdate';

const { ccclass, executionOrder } = cc._decorator;

enum KeyState {
    none,
    down,
    stay,
    up,
}
@ccclass('FixedKeyInput')
@executionOrder(-99)
export class FixedKeyInput extends cc.Component {
    static _instance: FixedKeyInput = null!;
    static get instance() {
        return this._instance;
    }

    // 用于记录当前帧的按键状态（改为 Set）
    private current: Set<number> = new Set<number>();
    // 用于记录上一帧的按键状态（改为 Set）
    private last: Set<number> = new Set<number>();

    __preload() {
        FixedKeyInput._instance = this;
    }

    start() {
        cc.input.on(cc.Input.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.input.on(cc.Input.EventType.KEY_UP, this.onKeyUp, this);
        //游戏进入后台时触发
        cc.game.on(cc.Game.EVENT_HIDE, this._resetKey, this);

        FixedUpdate.instance.node.on(
            FixedUpdate.EventFixedUpdate,
            this.fixedUpdate,
            this,
        );
    }

    fixedUpdate(frameIndex: number) {
        this.last.clear();
        for (const key of this.current) {
            this.last.add(key);
        }
    }

    private onKeyDown(key: cc.EventKeyboard) {
        this.current.add(key.keyCode);
    }

    private onKeyUp(key: cc.EventKeyboard) {
        this.current.delete(key.keyCode);
    }

    /**
     * 获取被按下的键
     * @param key
     * @returns
     */
    public getKey(key: number) {
        return this.current.has(key);
    }

    /**
     * 检测本帧某个按键是否刚被按下
     * @param key
     */
    public getKeyDown(key: number) {
        return this.checkType(key) === KeyState.down;
    }

    private checkType(key: number): KeyState {
        const last = this.last.has(key);
        const now = this.current.has(key);
        if (!last && now) {
            return KeyState.down;
        }
        if (last && now) {
            return KeyState.stay;
        }
        if (last && !now) {
            return KeyState.up;
        }
        return KeyState.none;
    }

    /**
     * 检测本帧某个按键是否刚被松开
     * @param key
     */
    public getKeyUp(key: number) {
        return this.checkType(key) === KeyState.up;
    }

    private _resetKey() {
        this.current.clear();
        this.last.clear();
    }
}
